#ifndef __AT_SERVER_H__
#define __AT_SERVER_H__

/*--- Data Types ------------------------------------------------------------*/
#define utlSUCCESS 0
#define utlFAILED -1

typedef enum ATCI_RESULT_CODE
{
    ATCI_RESULT_CODE_NULL,      // Timer will not stop
    ATCI_RESULT_CODE_OK,        // Timer will stop, OK will be sent
    ATCI_RESULT_CODE_ERROR,     // Timer will stop, ERROR will be sent
    ATCI_RESULT_CODE_CME_ERROR, // Timer will Stop, CME ERROR will be sent
    ATCI_RESULT_CODE_CMS_ERROR, // Timer will Stop, CMS ERROR will be sent
    ATCI_RESULT_CODE_SUPPRESS,  // Timer will Stop, End of AT response without OK or ERROR string
    ATCI_RESULT_CODE_CME_ERROR_PROXY,
    ATCI_RESULT_CODE_CMS_ERROR_PROXY,
    ATCI_RESULT_CODE_CMUX_ERROR,
    ATCI_RESULT_CODE_M2M_ERROR,
    ATCI_RESULT_CODE_MAX
} _AtciResultCode;

typedef int TelAtParserID; /* identifier AT Parser Number */

typedef int utlReturnCode_T, *utlReturnCode_P;
typedef const utlReturnCode_T *utlReturnCode_P2c;

typedef enum
{
    utlAT_DATA_TYPE_DECIMAL,
    utlAT_DATA_TYPE_HEXADECIMAL,
    utlAT_DATA_TYPE_BINARY,
    utlAT_DATA_TYPE_STRING,  /* string double-quotes are optional */
    utlAT_DATA_TYPE_QSTRING, /* string double-quotes are required */
    utlAT_DATA_TYPE_DIAL_STRING,
} utlAtDataType_T;

typedef enum
{
    utlAT_PARAMETER_ACCESS_READ_WRITE, /* reads and writes  are permitted    */
    utlAT_PARAMETER_ACCESS_READ,       /* attempts to write are ignored      */
    utlAT_PARAMETER_ACCESS_READ_ONLY,  /* attempts to write generates errors */
    utlAT_PARAMETER_ACCESS_WRITE_ONLY  /* attempts to read  generates errors */
} utlAtParameterAccess_T;

typedef enum
{
    utlAT_PARAMETER_PRESENCE_OPTIONAL, /* parameter presence is optional */
    utlAT_PARAMETER_PRESENCE_REQUIRED, /* parameter presence is required */
} utlAtParameterPresence_T;

typedef union utlAtDataValue_U
{
    unsigned int decimal;
    unsigned int hexadecimal;
    unsigned int binary;
    char *string_p;
    char *qstring_p;
    char *dial_string_p;
} utlAtDataValue_T, *utlAtDataValue_P;

typedef struct utlAtParameterValue_S
{
    utlAtDataType_T type; /* data type of `value' */
    utlAtParameterAccess_T access;
    BOOL is_default;        /* is `value' set to the default value? */
    utlAtDataValue_T value; /* parameter's value                    */
} utlAtParameterValue_T, *utlAtParameterValue_P;
typedef const utlAtParameterValue_T *utlAtParameterValue_P2c;

typedef struct utlAtParameter_S
{
    utlAtDataType_T type; /* parameter's data type */
    utlAtParameterAccess_T access;
    utlAtParameterPresence_T presence;
} utlAtParameter_T, *utlAtParameter_P;
typedef const utlAtParameter_T *utlAtParameter_P2c;

/*--- convenience macros ---*/
#define utlDEFINE_BASIC_AT_PARAMETER(type)                                         \
    {                                                                              \
        type, utlAT_PARAMETER_ACCESS_READ_WRITE, utlAT_PARAMETER_PRESENCE_OPTIONAL \
    }
#define utlDEFINE_DECIMAL_AT_PARAMETER(access, presence) \
    {                                                    \
        utlAT_DATA_TYPE_DECIMAL, access, presence        \
    }
#define utlDEFINE_HEXADECIMALL_AT_PARAMETER(access, presence) \
    {                                                         \
        utlAT_DATA_TYPE_HEXADECIMAL, access, presence         \
    }
#define utlDEFINE_BINARY_AT_PARAMETER(access, presence) \
    {                                                   \
        utlAT_DATA_TYPE_BINARY, access, presence        \
    }
#define utlDEFINE_STRING_AT_PARAMETER(access, presence) \
    {                                                   \
        utlAT_DATA_TYPE_STRING, access, presence        \
    }
#define utlDEFINE_QSTRING_AT_PARAMETER(access, presence) \
    {                                                    \
        utlAT_DATA_TYPE_QSTRING, access, presence        \
    }
#define utlDEFINE_DIAL_STRING_AT_PARAMETER(access, presence) \
    {                                                        \
        utlAT_DATA_TYPE_DIAL_STRING, access, presence        \
    }

/*--- parameter operations ---*/
typedef enum
{
    utlAT_PARAMETER_OP_UNKNOWN,
    utlAT_PARAMETER_OP_EXEC,
    utlAT_PARAMETER_OP_GET,
    utlAT_PARAMETER_OP_SET,
    utlAT_PARAMETER_OP_ACTION,
    utlAT_PARAMETER_OP_SYNTAX
} utlAtParameterOp_T, *utlAtParameterOp_P;

/*--- call-backs ---*/
typedef utlReturnCode_T (*utlAtGetParameterFunction_P)(const utlAtParameterOp_T op, const char *command_name_p, const utlAtParameterValue_P2c parameter_values_p, const size_t num_parameters, const char *info_text_p, unsigned int *xid_p, void *arg_p);
typedef utlReturnCode_T (*utlAtSetParameterFunction_P)(const utlAtParameterOp_T op, const char *command_name_p, const utlAtParameterValue_P2c parameter_values_p, const size_t num_parameters, const char *info_text_p, unsigned int *xid_p, void *arg_p);
typedef utlReturnCode_T (*utlAtCommandSyntaxFunction_P)(const utlAtParameterOp_T op, const char *command_name_p, const utlAtParameterValue_P2c parameter_values_p, const size_t num_parameters, const char *info_text_p, unsigned int *xid_p, void *arg_p);

typedef enum
{
    utlAT_COMMAND_TYPE_BASIC,             /* basic AT command              */
    utlAT_COMMAND_TYPE_EXTENDED,          /* extended-parameter AT command */
    utlAT_COMMAND_TYPE_EXACTION,          /* extended-action    AT command */
    utlAT_COMMAND_TYPE_EXTENDED_EXACTION, /*extended-parameter & extended-action AT command*/
    utlAT_COMMAND_TYPE_UNKNOWN
} utlAtCommandType_T;

typedef struct utlAtCommand_S
{
    utlAtCommandType_T type; /* AT-Command type */
    const char *name_p;      /* AT-Command name */

    utlAtParameter_P parameters_p; /* NULL pointer, or pointer to a variable-length array      */
    size_t num_parameters;         /* number of elements in array pointed to by `parameters_p' */

    struct
    {
        const char *command_syntax_p; /* AT-Command usage string (for syntax queries) */
        struct
        {
            utlAtCommandSyntaxFunction_P command_syntax_function_p;
        } call_backs;
    } usage;

    struct
    {
        utlAtGetParameterFunction_P get_parameter_function_p; /* for get requests          */
        utlAtSetParameterFunction_P set_parameter_function_p; /* for set & action requests */
    } call_backs;
} utlAtCommand_T, *utlAtCommand_P;

#define utlDEFINE_BASIC_AT_COMMAND(name, parameters_p, exec_function_p) \
    {                                                                   \
        utlAT_COMMAND_TYPE_BASIC, name, parameters_p,                   \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),            \
            {NULL, {NULL}}, { NULL, exec_function_p }                   \
    }

#define utlDEFINE_EXTENDED_AT_COMMAND(name, parameters_p, syntax, get_function_p, set_function_p) \
    {                                                                                             \
        utlAT_COMMAND_TYPE_EXTENDED, name, parameters_p,                                          \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                                      \
            {syntax, {NULL}}, { get_function_p, set_function_p }                                  \
    }

#define utlDEFINE_EXACTION_AT_COMMAND(name, parameters_p, syntax, action_function_p) \
    {                                                                                \
        utlAT_COMMAND_TYPE_EXACTION, name, parameters_p,                             \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                         \
            {syntax, {NULL}}, { NULL, action_function_p }                            \
    }

#define utlDEFINE_EXTENDED_VSYNTAX_AT_COMMAND(name, parameters_p, syntax_function_p, get_function_p, set_function_p) \
    {                                                                                                                \
        utlAT_COMMAND_TYPE_EXTENDED, name, parameters_p,                                                             \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                                                         \
            {NULL, {syntax_function_p}}, { get_function_p, set_function_p }                                          \
    }

#define utlDEFINE_EXACTION_VSYNTAX_AT_COMMAND(name, parameters_p, syntax_function_p, action_function_p) \
    {                                                                                                   \
        utlAT_COMMAND_TYPE_EXACTION, name, parameters_p,                                                \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                                            \
            {NULL, {syntax_function_p}}, { NULL, action_function_p }                                    \
    }

#define utlDEFINE_EXTENDED_EXACTION_AT_COMMAND(name, parameters_p, syntax, get_function_p, action_function_p) \
    {                                                                                                         \
        utlAT_COMMAND_TYPE_EXACTION, name, parameters_p,                                                      \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                                                  \
            {syntax, {NULL}}, { get_function_p, action_function_p }                                           \
    }

#define utlDEFINE_EXTENDED_EXACTION_VSYNTAX_AT_COMMAND(name, parameters_p, syntax_function_p, get_function_p, action_function_p) \
    {                                                                                                                            \
        utlAT_COMMAND_TYPE_EXTENDED_EXACTION, name, parameters_p,                                                                \
            sizeof(parameters_p) / sizeof(utlAtParameter_T),                                                                     \
            {NULL, {syntax_function_p}}, { get_function_p, action_function_p }                                                   \
    }

/******************************************************************************
*   Register user defined AT
******************************************************************************/
int at_command_register(const utlAtCommand_T *commands_p, size_t num_commands);

/******************************************************************************
*   Get AT handle from At Parser ID
******************************************************************************/
UINT32 at_command_make_at_handle(TelAtParserID sAtpIndex);

/******************************************************************************
*   utility parse functions
******************************************************************************/
BOOL getExtValue( const utlAtParameterValue_P2c param_value_p, int index, int *value_p, int minValue, int maxValue, int DefaultValue);

BOOL getExtUValue(const utlAtParameterValue_P2c param_value_p, int index, unsigned int *value_p, unsigned int minValue, unsigned int maxValue, unsigned int DefaultValue);

BOOL getExtString ( const utlAtParameterValue_P2c param_value_p, int index, CHAR *outString, INT16 maxStringLength, INT16 *outStringLength, CHAR *defaultString);

/******************************************************************************
*   Response (RESP) related Macro / inline functions
******************************************************************************/
int atRespStr(UINT32 reqHandle, UINT8 resultCode, UINT16 errCode, char *respString);

#define IND_REQ_HANDLE 1
#define IND_REQ_HANDLE_1 2

#define ATRESP(REQHANDLE, RESULTCODE, ERRCODE, RESPSTRING) atRespStr( REQHANDLE, RESULTCODE, ERRCODE, RESPSTRING )

#endif /*__AT_SERVER_H__*/
